/*=====================================================================================================================
                    Copyright(c) 2009 Geometric PLM Software Corp. All rights reserved.
                             Unpublished - All rights reserved
=======================================================================================================================
File description:
    Filename: tc_oci.c
    Module  : (geometric) itk module.

        This file manages the operations of OCI(Oracle Call Interface).

        OCI is the method of connecting the oracle supply by oracle with c/c++/java
        
        You need to include $ORACLE_HOME\OCI\include and $ORACLE_HOME\OCI\lib into your project configuration.
=======================================================================================================================
Date               Name              Description of Change
29-Jul-2009        Penn,Xie          Initialize creation
$HISTORY$
=====================================================================================================================*/
#ifndef _cplusplus
#define _CRT_SECURE_NO_DEPRECATE
#endif

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "tc_oci.h"

/**
* Error procedure
*/
int error_proc( dvoid *errhp, sword status ) 
{ 
    text errbuf[520];
    sb4  errcode; 
    switch (status) 
    { 
    case OCI_SUCCESS: 
        //                      printf("OCI_SUCCESS\n"); 
        break; 
    case OCI_SUCCESS_WITH_INFO:
        printf( "[OCI error]: OCI_SUCCESS_WITH_INFO\n" );
        break; 
    case OCI_NEED_DATA: 
        printf( "[OCI error]: OCI_NEED_DATA\n" );
        break; 
    case OCI_NO_DATA: 
        printf( "[OCI error]: OCI_NO_DATA\n" );
        break; 
    case OCI_ERROR:
        OCIErrorGet( (dvoid *)errhp, (ub4)OCI_HTYPE_FIRST, NULL, &errcode, errbuf, (ub4)sizeof(errbuf), OCI_HTYPE_ERROR ); 
        printf( "[OCI error]...%d\n.....%s\n", errcode, errbuf ); 
        break; 
    case OCI_INVALID_HANDLE: 
        printf( "[OCI error]: OCI_INVALID_HANDLE\n" ); 
        break; 
    case OCI_STILL_EXECUTING: 
        printf( "[OCI error]: OCI_STILL_EXECUTING\n" ); 
        break; 
    default: 
        break; 
    }
    return status;
} 

int GOCI_creat_evn_handle( OCIData_t *data )
{ 
    sword re;
    if (data == NULL)
        return OCI_ERROR;

    re = OCIEnvCreate( &(data->env), OCI_DEFAULT,(dvoid *)0, 0, 0, 0, 0, (dvoid **)0 );
    if (re != OCI_SUCCESS)
    {
        return re;
    }
    re = OCIHandleAlloc( (dvoid *)data->env, (dvoid **)&(data->error), OCI_HTYPE_ERROR, 0, (dvoid **)0 ); 
    if(re != 0)
    {
        printf( "[OCI error]: creation fail!" );
        return re;
    }
    re = error_proc( data->error, OCIHandleAlloc( (dvoid *)data->env, (dvoid **)&(data->svc), OCI_HTYPE_SVCCTX, 0, 0 ) );
    return re;
}

int GOCI_commit( OCIData_t *data )
{
    sword status;
    if (data == NULL || data->env == NULL)
        return OCI_ERROR;

    status = OCITransCommit( data->svc, data->error, OCI_DEFAULT );
    error_proc( data->error, status );
    return status;
}

int GOCI_rollback( OCIData_t *data )
{
    sword status;
    if (data == NULL || data->env == NULL)
        return OCI_ERROR;

    status = OCITransRollback( data->svc, data->error, OCI_DEFAULT );
    error_proc( data->error, status );
    return status;
}

int GOCI_logon( OCIData_t *data, const char *user, const char *pwd, const char *servername )
{
    sword status;
    if (data == NULL)
        return OCI_ERROR;

    status = OCILogon( data->env, data->error, &(data->svc),
                       (CONST OraText *)user,       (ub4)strlen(user),
                       (CONST OraText *)pwd,        (ub4)strlen(pwd ),
                       (CONST OraText *)servername, (ub4)strlen(servername) ); 
    if (status != OCI_SUCCESS)
    { 
        printf("[OCI error]: logon fail\n"); 
        error_proc( data->error, status );
    }

    return status;
}

int GOCI_logon_ip(OCIData_t *data, const char *ip, int port, const char *user, const char *pwd, const char *servername )
{
    sword status;
    char dblink[520];
    if (data == NULL)
        return OCI_ERROR;

    sprintf(dblink, "(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=%s)(PORT=%d)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=%s)))",
        ip, (port == -1 ? 1521 : port), servername);

    status = OCILogon( data->env, data->error, &(data->svc),
        (CONST OraText *)user,       (ub4)strlen(user),
        (CONST OraText *)pwd,        (ub4)strlen(pwd ),
        (CONST OraText *)dblink,     (ub4)strlen(dblink) ); 
    if (status != OCI_SUCCESS)
    { 
        printf("[OCI error]: logon with ip fail\n"); 
        error_proc( data->error, status );
    }

    return status;
}

int GOCI_stmt_prepare( OCIData_t *data, const char *sql )
{
    sword status;
    if (data == NULL)
        return OCI_ERROR;

    status = error_proc( data->error,
                         OCIHandleAlloc( (dvoid *)data->env, (dvoid **)&(data->sql), OCI_HTYPE_STMT, 0, 0 ) );
    if (status != OCI_SUCCESS)
        return status;
    status = error_proc( data->error,
                         OCIStmtPrepare( data->sql, data->error, (CONST OraText *)sql, (ub4)strlen(sql), (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT ) ); 
    return status;
} 

int GOCI_define_by_pos( OCIData_t *data, int pos, char *out, ub2 type )
{
    int MAX_DEP = 50;
    if (data == NULL)
        return OCI_ERROR;

    return error_proc( data->error,
                       OCIDefineByPos( data->sql, &(data->define), data->error, pos, 
                            (dvoid *) out, (sword)MAX_DEP, type, (dvoid *)0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT ) );
} 

sword GOCI_stmt_execute( OCIData_t *data )
{ 
    sword status;
    if (data == NULL)
        return OCI_ERROR;

    status = OCIStmtExecute(data->svc, data->sql, data->error, (ub4)1, (ub4)0, (CONST OCISnapshot *)NULL, (OCISnapshot *) NULL, OCI_DEFAULT);
    if (status == OCI_NO_DATA) 
    {
        // For select
    }
    else if (status != OCI_SUCCESS && status != OCI_SUCCESS_WITH_INFO)
    {
        // For update.insert
        error_proc( data->error, status ); 
        return OCI_ERROR; 

    }
    return status;
}

int GOCI_stmt_fetch( OCIData_t *data )
{ 
    return OCIStmtFetch( data->sql, data->error, 1, 0, 0 ); 
} 

void GOCI_handle_free( OCIData_t *data )
{
    if (data == NULL || data->env == NULL)
        return;

    OCILogoff( data->svc, data->error );
    OCIHandleFree(data->sql, OCI_HTYPE_STMT);
    OCIHandleFree(data->svc, OCI_HTYPE_SVCCTX); 
    OCIHandleFree(data->error, OCI_HTYPE_ERROR); 
}
